#
#   Albow - File Dialogs
#

import os
from pygame import draw, Rect
from albow.widget import Widget
from albow.dialogs import Dialog, ask, alert
from albow.controls import Label, Button 
from albow.fields import TextField
from albow.layout import Row, Column
from albow.palette_view import PaletteView
from albow.theme import ThemeProperty

class DirPathView(Widget):

	def __init__(self, width, client, **kwds):
		Widget.__init__(self, **kwds)
		self.set_size_for_text(width)
		self.client = client
	
	def draw(self, surf):
		frame = self.get_margin_rect()
		image = self.font.render(self.client.directory, True, self.fg_color)
		tw = image.get_width()
		mw = frame.width
		if tw <= mw:
			x = 0
		else:
			x = mw - tw
		surf.blit(image, (frame.left + x, frame.top))


class FileListView(PaletteView):

	#scroll_button_color = (255, 255, 0)

	def __init__(self, width, client, **kwds):
		font = self.predict_font(kwds)
		h = font.get_linesize()
		d = 2 * self.predict(kwds, 'margin')
		PaletteView.__init__(self, (width - d, h), 10, 1, scrolling = True, **kwds)
		self.client = client
		self.selection = None
		self.names = []
	
	def update(self):
		client = self.client
		dir = client.directory
		suffixes = client.suffixes
		def filter(name):
			path = os.path.join(dir, name)
			return os.path.isdir(path) or self.client.filter(path)
		try:
			names = [name for name in os.listdir(dir)
				if not name.startswith(".") and filter(name)]
		except EnvironmentError, e:
			alert("%s: %s" % (dir, e))
			names = []
		self.names = names
		self.selection = None
	
	def num_items(self):
		return len(self.names)
	
	#def draw_prehighlight(self, surf, item_no, rect):
	#	draw.rect(surf, self.sel_color, rect)
	
	def draw_item(self, surf, item_no, rect):
		font = self.font
		color = self.fg_color
		buf = self.font.render(self.names[item_no], True, color)
		surf.blit(buf, rect)
	
	def click_item(self, item_no, e):
		self.selection = item_no
		self.client.dir_box_click(e.num_clicks == 2)
	
	def item_is_selected(self, item_no):
		return item_no == self.selection
	
	def get_selected_name(self):
		sel = self.selection
		if sel is not None:
			return self.names[sel]
		else:
			return ""
		

class FileDialog(Dialog):

	box_width = 250
	default_prompt = None
	up_button_text = ThemeProperty("up_button_text")

	def __init__(self, prompt = None, suffixes = None, **kwds):
		Dialog.__init__(self, **kwds)
		label = None
		d = self.margin
		self.suffixes = suffixes or ()
		up_button = Button(self.up_button_text, action = self.go_up)
		dir_box = DirPathView(self.box_width - up_button.width - 10, self)
		self.dir_box = dir_box
		top_row = Row([dir_box, up_button])
		list_box = FileListView(self.box_width - 16, self)
		self.list_box = list_box
		ctrls = [top_row, list_box]
		prompt = prompt or self.default_prompt
		if prompt:
			label = Label(prompt)
		if self.saving:
			filename_box = TextField(self.box_width)
			filename_box.change_action = self.update
			self.filename_box = filename_box
			ctrls.append(Column([label, filename_box], align = 'l', spacing = 0))
		else:
			if label:
				ctrls.insert(0, label)
		ok_button = Button(self.ok_label, action = self.ok, enable = self.ok_enable)
		self.ok_button = ok_button
		cancel_button = Button("Cancel", action = self.cancel)
		vbox = Column(ctrls, align = 'l', spacing = d)
		vbox.topleft = (d, d)
		y = vbox.bottom + d
		ok_button.topleft = (vbox.left, y)
		cancel_button.topright = (vbox.right, y)
		self.add(vbox)
		self.add(ok_button)
		self.add(cancel_button)
		self.shrink_wrap()
		self._directory = None
		self.directory = os.getcwd()
		#print "FileDialog: cwd =", repr(self.directory) ###
		if self.saving:
			filename_box.focus()
	
	def get_directory(self):
		return self._directory
	
	def set_directory(self, x):
		x = os.path.abspath(x)
		while not os.path.exists(x):
			y = os.path.dirname(x)
			if y == x:
				x = os.getcwd()
				break
			x = y
		if self._directory <> x:
			self._directory = x
			self.list_box.update()
			self.update()
	
	directory = property(get_directory, set_directory)
	
	def filter(self, path):
		suffixes = self.suffixes
		if not suffixes:
			return os.path.isfile(path)
		for suffix in suffixes:
			if path.endswith(suffix):
				return True
	
	def update(self):
		pass
	
	def go_up(self):
		self.directory = os.path.dirname(self.directory)
	
	def dir_box_click(self, double):
		if double:
			name = self.list_box.get_selected_name()
			path = os.path.join(self.directory, name)
			suffix = os.path.splitext(name)[1]
			if suffix not in self.suffixes and os.path.isdir(path):
				self.directory = path
			else:
				self.double_click_file(name)
		self.update()
	
	def ok(self):
		self.dismiss(True)
	
	def cancel(self):
		self.dismiss(False)
	

class FileSaveDialog(FileDialog):

	saving = True
	default_prompt = "Save as:"
	ok_label = "Save"
	
	def get_filename(self):
		return self.filename_box.value
	
	def set_filename(self, x):
		dsuf = self.suffixes[0]
		if x.endswith(dsuf):
			x = x[:-len(dsuf)]
		self.filename_box.value = x
	
	filename = property(get_filename, set_filename)

	def get_pathname(self):
		path = os.path.join(self.directory, self.filename_box.value)
		suffixes = self.suffixes
		if suffixes and not path.endswith(suffixes[0]):
			path = path + suffixes[0]
		return path
	
	pathname = property(get_pathname)
	
	def double_click_file(self, name):
		self.filename_box.value = name

	def ok(self):
		path = self.pathname
		if os.path.exists(path):
			answer = ask("Replace existing '%s'?" % os.path.basename(path))
			if answer <> "OK":
				return
		FileDialog.ok(self)

	def update(self):
		FileDialog.update(self)
	
	def ok_enable(self):
		return self.filename_box.text <> ""
	

class FileOpenDialog(FileDialog):

	saving = False
	ok_label = "Open"
	
	def get_pathname(self):
		name = self.list_box.get_selected_name()
		if name:
			return os.path.join(self.directory, name)
		else:
			return None

	pathname = property(get_pathname)
	
	#def update(self):
	#	FileDialog.update(self)
	
	def ok_enable(self):
		path = self.pathname
		enabled = self.item_is_choosable(path)
		return enabled
	
	def item_is_choosable(self, path):
		return bool(path) and self.filter(path)
	
	def double_click_file(self, name):
		self.ok()


class LookForFileDialog(FileOpenDialog):

	target = None

	def __init__(self, target, **kwds):
		FileOpenDialog.__init__(self, **kwds)
		self.target = target
	
	def item_is_choosable(self, path):
		return path and os.path.basename(path) == self.target

	def filter(self, name):
		return name and os.path.basename(name) == self.target


def request_new_filename(prompt = None, suffix = None, extra_suffixes = None,
		directory = None, filename = None, pathname = None):
	if pathname:
		directory, filename = os.path.split(pathname)
	if extra_suffixes:
		suffixes = extra_suffixes
	else:
		suffixes = []
	if suffix:
		suffixes = [suffix] + suffixes
	dlog = FileSaveDialog(prompt = prompt, suffixes = suffixes)
	if directory:
		dlog.directory = directory
	if filename:
		dlog.filename = filename
	if dlog.present():
		return dlog.pathname
	else:
		return None

def request_old_filename(suffixes = None, directory = None):
	dlog = FileOpenDialog(suffixes = suffixes)
	if directory:
		dlog.directory = directory
	if dlog.present():
		return dlog.pathname
	else:
		return None

def look_for_file_or_directory(target, prompt = None, directory = None):
	dlog = LookForFileDialog(target = target, prompt = prompt)
	if directory:
		dlog.directory = directory
	if dlog.present():
		return dlog.pathname
	else:
		return None
